package com.hardson.toolkit.util;

import java.lang.reflect.Array;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Lists {

    public static <T> ArrayList<T> EMPTY_LIST() {
        return new ArrayList<>(0);
    }

    public static <T> ArrayList<T> arrayList() {
        return new ArrayList<>();
    }

    public static <E> ArrayList<E> arrayList(Collection<? extends E> c) {
        return c == null ? new ArrayList<E>(0) : new ArrayList<>(c);
    }

    public static <T> ArrayList<T> arrayList(int initialCapacity) {
        return new ArrayList<>(initialCapacity);
    }

    public static <T> LinkedList<T> linkedList() {
        return new LinkedList<>();
    }

    public static <E> LinkedList<E> linkedList(Collection<? extends E> c) {
        return new LinkedList<>(c);
    }

    /**
     * 将数组对象转化为ArrayList对象。
     * 注：Arrays.asList()方法转化的是其内部ArrayList对象，与通用ArrayList对象有差异，有些场景不适用，因此提供此方法
     *
     * @param element 元素数组
     * @return List<T>
     */
    @SafeVarargs
    public static <T> List<T> asList(T... element) {
        if (element == null || element.length == 0) {
            return EMPTY_LIST();
        }
        List<T> list = arrayList(element.length);
        Collections.addAll(list, element);
        return list;
    }

    @SafeVarargs
    public static <T> LinkedList<T> asLinkedList(T... element) {
        if (element == null || element.length == 0) {
            return linkedList();
        }
        LinkedList<T> list = new LinkedList<>();
        Collections.addAll(list, element);
        return list;
    }

    /**
     * 将元素类型为T2的列表强制转化成元素类型为T1的ArrayList列表
     *
     * @param oriList 被转化集合
     * @return List<T1>
     */
    @SuppressWarnings("unchecked")
    public static <T1, T2> List<T1> convert(Collection<T2> oriList) {
        return oriList.stream().map((t2) -> (T1) t2).collect(Collectors.toList());
    }

    /**
     * 根据给出的对象查找集合中某一属性与该对象equals相同的集合内对象，并返回该集合内对象的指定属性。
     *
     * @param collection       要检索的集合
     * @param comparedObj      用于检索过滤的对象
     * @param fieldValueGetter 通过该函数式接口获取要比较的集合内对象指定属性值
     * @param resultFunc       通过该函数式接口返回集合内对象指定属性值
     * @return 通过函数式接口返回的所查到的集合内对象的属性值
     */
    public static <T, R> R find(Collection<T> collection, Object comparedObj, Function<T, R> fieldValueGetter,
                                Function<T, R> resultFunc) {
        return collection.stream().filter(t -> Objects.equals(comparedObj, fieldValueGetter.apply(t))).findFirst()
                .map(resultFunc).orElse(null);
    }

    public static <T> String find(Collection<T> collection, String comparedStr,
                                  Function<T, String> fieldValueGetter, Function<T, String> resultFunc) {
        return find(collection, comparedStr, fieldValueGetter, resultFunc, true);
    }

    /**
     * 根据给出的字符串查找集合中某一属性与该字符串相同的集合内对象，并返回该集合内对象的指定属性。
     *
     * @param collection       要检索的集合
     * @param comparedStr      用于检索过滤的字符串
     * @param fieldValueGetter 通过该函数式接口获取要比较的集合内对象指定属性值
     * @param resultFunc       通过该函数式接口返回集合内对象指定属性值
     * @param caseSensitive    大小写是否敏感,true区分大小写，false不分大小写
     * @return 通过函数式接口返回的所查到的集合内对象的属性值，没有找到时返回空字符串""
     */
    public static <T> String find(Collection<T> collection, String comparedStr,
                                  Function<T, String> fieldValueGetter, Function<T, String> resultFunc,
                                  boolean caseSensitive) {
        return collection.stream()
                .filter(t -> caseSensitive ? Objects.equals(comparedStr, fieldValueGetter.apply(t))
                        : comparedStr.equalsIgnoreCase(fieldValueGetter.apply(t)))
                .findFirst().map(resultFunc).orElse("");
    }

    /**
     * 根据给出的对象查找集合中某一属性与该对象equals比较相同的集合内对象，并返回该集合内对象。
     *
     * @param collection       要检索的集合
     * @param comparedObj      用于检索过滤的对象（equals方法比较）
     * @param fieldValueGetter 通过该函数式接口获取要比较的集合内对象指定属性值
     * @return 返回所查到的集合内对象
     */
    public static <T, R> T find(Collection<T> collection, Object comparedObj, Function<T, R> fieldValueGetter) {
        return collection.stream().filter(t -> Objects.equals(comparedObj, fieldValueGetter.apply(t))).findFirst()
                .orElse(null);
    }

    /**
     * 过滤列表，剔出不符合decideFunc判断的元素
     *
     * @param collection-要过滤的集合
     * @param decideFunc-用于判定是否符合条件
     * @return List<T> 符合decideFunc判断的元素集合
     * @author hardson
     * @date 2023/10/22 下午1:35
     */
    public static <T> List<T> filter(Collection<T> collection, Function<T, Boolean> decideFunc) {
        return collection.stream().filter(decideFunc::apply).collect(Collectors.toList());
    }

    /**
     * 将以特定分隔符连接的字符串转化为整数ArrayList列表 如"12,34,56"转化成ArrayList包含12、34、56整型元素
     *
     * @param str       被解析的字符串
     * @param seperator 分隔字符串
     * @return List<Integer>
     */
    public static List<Integer> stringToIntList(String str, String seperator) {
        if (StrUtil.isTrimEmpty(str)) {
            return EMPTY_LIST();
        }
        String[] arr = str.split(seperator);
        return Stream.of(arr).map(String::trim).filter(s -> !s.isEmpty()).map(Integer::valueOf)
                .collect(Collectors.toList());
    }

    /**
     * 将以特定分隔符连接的字符串转化为长整数ArrayList列表 如"12,34,56"转化成ArrayList包含12、34、56长整型元素
     *
     * @param str       被解析的字符串
     * @param seperator 分隔字符串
     * @return List<Long>
     */
    public static List<Long> stringToLongList(String str, String seperator) {
        if (StrUtil.isTrimEmpty(str)) {
            return EMPTY_LIST();
        }
        String[] arr = str.split(seperator);
        return Stream.of(arr).map(String::trim).filter(s -> !s.isEmpty()).map(Long::valueOf)
                .collect(Collectors.toList());
    }

    /**
     * 将以特定分隔符连接的字符串转化为字符串ArrayList列表 如"12,34,56"转化成ArrayList包含"12"、"34"、"56"字符串元素
     *
     * @param str       被解析的字符串
     * @param seperator 分隔字符串
     * @return List<String>
     */
    public static List<String> stringToList(String str, String seperator) {
        if (StrUtil.isTrimEmpty(str)) {
            return EMPTY_LIST();
        }
        return asList(str.split(seperator));
    }

    /**
     * 将列表中的对象进一步处理，并将处理结果形成列表返回
     *
     * @param list 待处理的列表
     * @param func 列表中对象的处理函数，返回处理结果
     * @return List<M>处理结果形成的列表
     */
    public static <M, T> List<M> toMemberList(Collection<T> list, Function<T, M> func) {
        return list.stream().map(func).collect(Collectors.toList());
    }

    /**
     * 将对象列表转换成Map对象，以指定的属性值作为key，key重复时，原key对应的对象被覆盖
     *
     * @param list 待转换列表
     * @param func 属性提到函数
     * @return Map<K, V>
     */
    public static <K, V> Map<K, V> toDistinctMap(Collection<V> list, Function<V, K> func) {
        return list.stream()
                .collect(Collectors.toMap(func, Function.identity(), (key1, key2) -> key2));
    }

    /**
     * 将对象列表转换成Map对象，以指定的属性值作为key
     * 注意：如果集合列表转成Map时，出现key重复的情况Collectors.toMap将抛出Duplicate key异常
     *
     * @param list 待转换列表
     * @param func 属性提取函数
     * @return Map<K, V>
     */
    public static <K, V> Map<K, V> toMap(Collection<V> list, Function<V, K> func) {
        return list.stream().collect(Collectors.toMap(func, Function.identity()));
    }

    /**
     * 将对象列表转换成Map对象，以指定的属性值作为key
     * 注意：如果集合列表转成Map时，出现key重复的情况，key的新值将覆盖旧值
     *
     * @param list 待转换列表
     * @param func 属性提取函数
     * @return Map<K, V>
     */
    public static <K, V> Map<K, V> toMapOfCover(Collection<V> list, Function<V, K> func) {
        return list.stream().collect(Collectors.toMap(func, Function.identity(), (oldVal, newVal) -> newVal));
    }

    /**
     * 将对象列表转换成Map对象，key和value均赋予指定的属性值
     * 注意：如果集合列表转成Map时，出现key重复的情况Collectors.toMap将抛出Duplicate key异常
     *
     * @param list  待转换列表
     * @param func  key提取函数
     * @param func1 value提取函数
     * @return Map<K, T>
     */
    public static <K, V, T> Map<K, T> toMap(Collection<V> list, Function<V, K> func, Function<V, T> func1) {
        return list.stream().collect(Collectors.toMap(func, func1));
    }

    /**
     * 将对象列表转换成Map对象，key和value均赋予指定的属性值
     * 注意：如果集合列表转成Map时，出现key重复的情况，key的新值将覆盖旧值
     *
     * @param list  待转换列表
     * @param func  key提取函数
     * @param func1 value提取函数
     * @return Map<K, T>
     */
    public static <K, V, T> Map<K, T> toMapOfCover(Collection<V> list, Function<V, K> func, Function<V, T> func1) {
        return list.stream().collect(Collectors.toMap(func, func1, (oldVal, newVal) -> newVal));
    }

    /**
     * 将对象列表转换成LinkedHashMap对象，以指定的属性值作为key
     *
     * @param list 待转换列表
     * @param func 属性提取函数
     * @return Map<K, V>
     */
    public static <K, V> Map<K, V> toLinkedHashMap(Collection<V> list, Function<V, K> func) {
        Map<K, V> map = new LinkedHashMap<>(list.size());
        list.forEach((v) -> map.put(func.apply(v), v));
        return map;
    }

    /**
     * 将对象列表分组，保存于map对象中，map中的key为分组的键值,一个key对象对应一组对象列表
     *
     * @param list       待转换列表
     * @param classifier key提取函数
     * @return Map<K, List < V>>
     */
    public static <K, V> Map<K, List<V>> groupingBy(Collection<V> list, Function<V, K> classifier) {
        return list.stream()
                .collect(Collectors.groupingBy(classifier, LinkedHashMap::new, Collectors.toList()));
    }

    /**
     * 对集合按照指定长度分段，每一个段为单独的集合，返回这个集合的列表
     *
     * @param collection 集合
     * @param size       每个段的长度
     * @return 分段列表
     */
    public static <T> List<List<T>> split(Collection<T> collection, int size) {
        if (isEmpty(collection)) {
            return EMPTY_LIST();
        }
        final List<List<T>> result = arrayList();
        List<T> subList = arrayList(size);
        for (T t : collection) {
            if (subList.size() >= size) {
                result.add(subList);
                subList = arrayList(size);
            }
            subList.add(t);
        }
        result.add(subList);
        return result;
    }

    /**
     * 将对象列表中的某一类型属性以分隔符连接成字符串
     *
     * @param list 待处理的对象列表
     * @param func
     * @param sep  分隔符
     * @return String
     */
    public static <K, T, V> String toSeparatString(Collection<T> list, Function<T, V> func, String sep) {
        Function<T, String> func1 = func.andThen(v -> Objects.toString(v, ""));
        return list.stream().map(func1).map(String::trim).filter(s -> !s.isEmpty())
                .collect(Collectors.joining(sep));
    }

    /**
     * 将字符串列表以分隔符连接成字符串
     *
     * @param list 字符串列表
     * @param sep  分隔符
     * @return String
     */
    public static String toSeparatString(Collection<String> list, String sep) {
        return list.stream().map(String::trim).filter(s -> !s.isEmpty())//
                .collect(Collectors.joining(sep));
    }

    public static boolean isEmpty(final Collection<?> list) {
        return list == null || list.isEmpty();
    }

    public static boolean isNotEmpty(final Collection<?> list) {
        return !isEmpty(list);
    }

    public static <T> List<T> emptyArrayListIfNull(List<T> list) {
        return list == null ? new ArrayList<>() : list;
    }

    public static <T> Vector<T> toVector(List<T> list) {
        return new Vector<>(list);
    }

    /**
     * 将集合转化成数组列表 <br/>
     * 集合元素的类型必须一致。
     *
     * @param collection    待转换集合
     * @param componentType 成员类型
     * @return T[]
     */
    public static <T> T[] toArray(Collection<T> collection, Class<T> componentType) {
        @SuppressWarnings("unchecked")
        T[] t = (T[]) Array.newInstance(componentType, collection.size());
        return collection.toArray(t);
    }

    /**
     * 用列表元素的字符串(toString())构造数据库查询条件IN的数字内容
     *
     * @param list 源列表
     * @return String
     */
    public static String toSqlInAsInt(List<Integer> list) {
        return list.stream().map(Object::toString).collect(Collectors.joining(","));
    }

    /**
     * 用列表元素的字符串(toString())构造数据库查询条件IN的数字内容
     *
     * @param list 源列表
     * @return String
     */
    public static String toSqlInAsNum(List<?> list) {
        return list.stream().map(Object::toString).collect(Collectors.joining(","));
    }

    /**
     * 用列表字符串构造数据库查询条件IN的字符串内容
     *
     * @param list 源列表
     * @return String
     */
    public static String toSqlInAsChar(List<String> list) {
        String fmt = "'%s'";
        return list.stream().map(String::trim).filter(s -> !s.isEmpty()).map(s -> String.format(fmt, s))
                .collect(Collectors.joining(","));
    }

    /**
     * 用列表数字构造数据库查询条件IN的字符串内容
     * 返回结果如：-->'1','2','3'
     *
     * @param list 源列表
     * @return String
     */
    public static String toSqlInAsCharFromInt(List<Integer> list) {
        String fmt = "'%s'";
        return list.stream().filter(Objects::nonNull).map(s -> String.format(fmt, s))
                .collect(Collectors.joining(","));
    }

    /**
     * 用对象列表中的某一属性值构造数据库查询条件In的字符串内容
     *
     * @param list 源列表
     * @param func 属性提取函数
     * @return String
     */
    public static <K, T, V> String toSqlInAsChar(Collection<T> list, Function<T, V> func) {
        String fmt = "'%s'";
        Function<T, String> func1 = func.andThen(v -> Objects.toString(v, "").trim());
        return list.stream().map(func1).filter(s -> !s.isEmpty()).map(s -> String.format(fmt, s))
                .collect(Collectors.joining(","));
    }

    public static String toSqlValuesQuestionMark(int count) {
        if (count < 1) {
            throw new IllegalArgumentException("count should be more than 0");
        }
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < count; i++) {
            b.append("?,");
        }
        return b.substring(0, b.length() - 1);
    }

    /**
     * 获取列表中的最后一个元素。如果列表为空则返回null
     *
     * @param list 列表
     * @return E 列表的最后一个元素
     * @author hardson
     * @date 2023/8/14 下午2:03
     */
    public static <E> E getLast(List<E> list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.get(list.size() - 1);
    }

    /**
     * 测试字符串列表中是否含有所提供的字符串（忽略大小写）
     *
     * @param stringList:
     * @param str:
     * @return boolean
     * @author hardson
     * @date 2024/8/13 下午2:56
     */
    public static boolean containsIgnoreCase(List<String> stringList, String str) {
        if (stringList == null || stringList.isEmpty()) {
            return false;
        }
        for (String s : stringList) {
            if (s.equalsIgnoreCase(str)) {
                return true;
            }
        }
        return false;
    }
}
